//! @file   lc_scoped_pointer.h
//! @brief  
//! @author Sayan Chaliha
//! @date   October, 2011
//!
//! 
#ifndef _LC_SCOPED_POINTER
#define _LC_SCOPED_POINTER

#include "libcyan_internal.h"
#include "lc_types.h"
#include "lc_object.h"

namespace cyan {
    template <typename T>
    class CYAN_API ScopedPointer : public Object {
    public:
        typedef T ValueType;
        
        explicit ScopedPointer(ValueType* object) : object_(object) {
        }
        
        virtual ~ScopedPointer() {
            delete this->object_;
        }
        
        inline ValueType& operator *() const {
            return *this->object_;
        }
        
        inline ValueType* operator ->() const {
            return this->object_;
        }
        
        inline operator ValueType*() const {
            return this->object_;
        }
        
        inline ValueType** operator &() const {
            return &this->object_;
        }
        
        inline void reset(ValueType* object = nullptr) {
            assertNotEqual(object, this->object_);
            
            ScopedPointer(object).swap(this->object_);
        }
        
        inline void swap(ScopedPointer& pointer) {
            ValueType* value = pointer.object_;
            pointer.object_ = this->object_;
            this->object_ = value;
        }

    private:
        ScopedPointer() {
        }
        
        ScopedPointer(const ScopedPointer&) {
        }
        
        ScopedPointer& operator =(const ScopedPointer&) {
        }
        
        ValueType* object_;
    };
    
    template <typename T>
    class CYAN_API ScopedArray : public Object {
    public:
        typedef T ValueType;
        
        explicit ScopedArray(ValueType* array = nullptr) : array_(array) {
        }
        
        virtual ~ScopedArray() {
            if (this->array_)
                delete [] this->array_;
        }
        
        inline ValueType& operator *() const {
            return *this->array_;
        }
        
        inline operator ValueType*() const {
            return this->array_;
        }
        
        inline ValueType** operator &() const {
            return &this->array_;
        }
        
        inline ValueType& operator [](PtrDiff index) const {
            assertNotNull(this->array_);
            assertGtOrEq(index, 0);
            
            return this->array_[index];
        }
        
        inline void reset(ValueType* object = nullptr) {
            assertNotEqual(object, this->object_);
            
            ScopedArray(object).swap(*this);
        }
        
        inline void swap(ScopedArray& array) {
            ValueType* value = array.array_;
            array.array_ = this->array_;
            this->array_ = value;
        }
        
    private:
        ScopedArray() {
        }
        
        ScopedArray(const ScopedArray&) {
        }
        
        ScopedArray& operator =(const ScopedArray&) {
        }
        
        ValueType* array_;
    };
}

#endif /* _LC_SCOPED_POINTER */
